/**
 * 版权所有 2009-2015 中国中医科学院中医药信息研究所 何前锋 frontpeak@yahoo.com.cn
 **/
package cn.ac.cintcm.sh.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jfree.data.category.DefaultCategoryDataset;

import cn.ac.cintcm.prespring.cluster.CalSimilarity;
import cn.ac.cintcm.prespring.cluster.Similarity;
import cn.ac.cintcm.prespring.tree.Ladder;
import cn.ac.cintcm.prespring.tree.VisitMemory;
import cn.ac.cintcm.prespring.tree.WebTree;
import cn.ac.cintcm.prespring.util.FileUtil;
import cn.ac.cintcm.prespring.util.IndexFile;
import cn.ac.cintcm.prespring.util.NameIndex;
import cn.ac.cintcm.sh.dao.HerbDao;
import cn.ac.cintcm.sh.dao.HsqldbDao;
import cn.ac.cintcm.sh.dao.PrescriptionDao;
import cn.ac.cintcm.sh.dao.ViewDao;
import cn.ac.cintcm.sh.domain.Conversion;
import cn.ac.cintcm.sh.domain.Conversions;
import cn.ac.cintcm.sh.domain.Prescription;
import cn.ac.cintcm.sh.domain.Prescriptions;
import cn.ac.cintcm.sh.domain.Qi9;
import cn.ac.cintcm.sh.domain.View;
/**
 * 方剂的索引、相似方剂、方剂内容、方剂原文、方剂树、寒热分析、剂量转换的服务
 * @author 何前锋 Franklin He(franklinheqf@gmail.com)
 *
 */
public class PrescriptionService {

    private PrescriptionDao prescriptionDao = new PrescriptionDao();
    private ViewDao viewDao = new ViewDao();
    private HerbDao herbDao = new HerbDao();
    private float defaultSimilarity = 2/3f;

    /**
     * 获取所有的方剂的名称
     * @return 方剂名称索引
     */
    public List<Prescription> getPresIndex() {
        List<Prescription> pres = prescriptionDao.getIndex();
        return pres;
    }
    
    /**
     * 获取单个方剂的完整信息，包括方剂的名称，组成，各组成中药的剂量，寒热值等信息
     * @param id 方剂的id
     * @return 单个方剂信息
     */
    public Prescription getPrescription(String id) {
        Prescription p = null;
        if (id != null) {
            p = prescriptionDao.getPrescription(Integer.parseInt(id));
        }
        return p;
    }
    
    /**
     * 获取多个方剂的完整信息，包括方剂的名称，组成，各组成中药的剂量，寒热值等信息
     * @param id 方剂的id
     * @return 单个方剂信息
     */
    public Collection<Prescription> getAllPrescriptions(String[] ids) {
        Collection<Prescription> p = null;
        if (ids != null) {
            p = prescriptionDao.getPrescriptionsAll(ids);
        }
        return p;
    }
    
    /**
     * 取得匹配特定字符串的方剂
     * @param name 字符串
     * @param isPrecise 是否精确匹配，值为字符串的"true"或者"false"
     * @return 符合匹配字符串条件的方剂
     */
    public List<Prescription> getPrescriptions(String name, String isPrecise) {
        boolean precise = false;
        try {
            precise = Boolean.parseBoolean(isPrecise);
        } catch (RuntimeException e) {
        }
        List<Prescription> pres = null;
        if (name != null && !name.trim().equals("")) {
            pres = prescriptionDao.getPrescriptions(name, precise);
        } else {
            pres = getPresIndex();
        }
        return pres;
    }
    
    /**
     * 取得包含1个或者多个中药的方剂
     * @param herbs 一个或者多个中药的名称，两个中药之间使用空格分隔
     * @param extendAlias 中药是否扩展为同异名的，即使用中药的异名，
     *                    或者将异名转换为正名去找符合的方剂，值为字符串的"true"或者"false"
     * @return 符合包含1个或者多个中药的方剂
     */
    public List<Prescription> getHerbsPrescriptions(String herbs, String extendAlias) {
        boolean  extended = false;
        try {
            extended = Boolean.parseBoolean(extendAlias);
        } catch (RuntimeException e) {
        }
        
        List<Prescription> pres = null;
        if (herbs != null) {
            herbs = herbs.trim();
            if (!herbs.equals("")) {
                String[] herbList = herbs.split(" ");
                pres = prescriptionDao.getPrescriptions(herbList, extended);
            }
        }
        return pres;
    }
    
    /**
     * 取得包含1个或者多个中药的方剂
     * @param herbIds 一个或者多个中药的id，
     * @param extendAlias 中药是否扩展为同异名
     * @return  符合包含1个或者多个中药的方剂
     */
    public List<Prescription> getPrescriptions(String[] herbIds) {
        Integer[] herbs = new Integer[herbIds.length];
        int i = 0;
        for (String s : herbIds) {
            herbs[i++] = Integer.parseInt(s);
        }
        List<Prescription> pres = prescriptionDao.getPrescriptions(herbs);
        return pres;
    }   
    /**
     * 取得在一定寒热值范围内的方剂
     * @param min 最小寒热值，取整数
     * @param max 最大寒热值，取整数
     * @return
     */
    public List<Prescription> getHCPrescriptions(String min, String max) {
        List<Prescription> pres = null;
        float minv = Qi9.MinValue;
        float maxv = Qi9.MaxValue;
        if (min != null) {
            try {
                float smin = Float.parseFloat(min);
                if (smin > minv  && smin < maxv) {
                    minv = smin;
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        if (max != null) {
            try {
                float smax = Float.parseFloat(max);
                if (smax > minv && smax < maxv) {
                    maxv = smax; 
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

        pres = prescriptionDao.getPrescriptions(minv, maxv);
        return pres;
    }
    
    /**
     * 多个观点的剂量折算
     * @param pid 方剂的id
     * @param viewids 折算观点的id
     * @return 使用折算观点对方剂剂量折算后的结果
     */
    public Conversions convert(int pid, int[] viewids) {
        //Prescription p = prescriptionDao.getPrescription(pid);
        //Collection<View> views = viewDao.getViews(viewids);
        Conversions cs = null;
        cs = new Conversions();
        for (int v : viewids) {
            Conversion c = convert(pid, v);
            cs.add(v, c);
        }

        return cs;
    }
    
    /**
     * 单个观点的剂量折算
     * @param pid 方剂的Id
     * @param viewid 折算观点的id
     * @return 使用折算观点对方剂剂量折算后的结果
     */
    public Conversion convert(int pid, int viewid) {
        Prescription p = prescriptionDao.getPrescription(pid);
        View view = viewDao.getView(viewid);
        Conversion c = null;
        if (p != null && view != null) {
            c = view.convert(p);
        }
        return c;
    }
    
    /**
     * 寒Hot热Cold分析树
     * @param pid 待分析的方剂id
     * @param viewid 使用的剂量折算分析观点Id
     * @return 寒热分析构成方剂树的javascript脚步语句字符串
     */
    public String getHCAnalysis(int pid, int viewid) {
        String result = null;
        Prescription p = prescriptionDao.getPrescription(pid);
        View view = viewDao.getView(viewid);
        //Conversion c = null;
        if (p != null && view != null) {
            view.convert(p);
            //p.setConversion(c);
            p.analysis();
            result = p.printTree();
        }
        return result;
    }
    
    /**
     * 自拟方寒Hot热Cold分析树
     * @param str 自拟方中药组成字符串
     * @return 寒热分析构成方剂树的javascript脚步语句字符串
     */
    public String getHCAnalysis(String str, int viewid) {
        String result = null;
        Prescription p = new Prescription();
        View view = viewDao.getView(viewid);
        p = p.parseHerb(str);
        if (p != null && view != null) {
            view.convert(p);
            p.analysis();
            result = p.printTree();
        }
        return result;
    }
    
    /**
     * 方剂组成药加Plus减Minus分析树
     * @param pid 待分析的方剂id
     * @return 所需分析方剂的加树和减树的javascript脚步语句字符串
     * @throws IOException 
     */
    public String getPMAnalysis(int pid) throws IOException {
        IndexFile prescriptionHerbs = prescriptionDao.getIndexFile();
        Ladder ld = new Ladder(prescriptionHerbs);
        VisitMemory vm = ld.getLadder(pid + "");
        NameIndex prescriptionsIndex = new NameIndex(prescriptionDao.getNameIndex());
        NameIndex herbsIndex = new NameIndex(herbDao.getNameIndex());
        
        String path = HsqldbDao.path;
        List<String> templateStrList = FileUtil.read(path, "template.txt");

        WebTree wt = new WebTree(herbsIndex,prescriptionsIndex);
        
        wt.setIndex(pid, prescriptionHerbs);
        wt.setTree(vm);
        wt.setLink("sim/?wt=xslt&tr=similar.xsl&q=id:");
        return wt.createWebTree(templateStrList).toString();
    }
    
    /**
     * 自拟方组成药加Plus减Minus分析树
     * @param str 自拟方中药组成字符串
     * @return 所需分析方剂的加树和减树的javascript脚步语句字符串
     * @throws IOException 
     */
    public String getPMAnalysis(String str) throws IOException {
        Prescription p = new Prescription();
        p = p.parseHerb(str);

        IndexFile prescriptionHerbs = prescriptionDao.getIndexFile();
        String pstr = p.getCompositStr();
        prescriptionHerbs.add(pstr);
        
        Ladder ld = new Ladder(prescriptionHerbs);
        VisitMemory vm = ld.getLadder(p.getId() + "");
        NameIndex prescriptionsIndex = new NameIndex(prescriptionDao.getNameIndex());
        prescriptionsIndex.addIdName(p.getId(), p.getName());
        NameIndex herbsIndex = new NameIndex(herbDao.getNameIndex());
        
        String path = HsqldbDao.path;
        List<String> templateStrList = FileUtil.read(path, "template.txt");

        WebTree wt = new WebTree(herbsIndex,prescriptionsIndex);
        
        wt.setIndex(p.getId(), prescriptionHerbs);
        wt.setTree(vm);
        wt.setLink("sim/?wt=xslt&tr=similar.xsl&q=id:");
        return wt.createWebTree(templateStrList).toString();
    }
    
    /**
     * 取得与输入方剂相似中药组成的方剂
     * @param pid 需要获取相似方剂的方
     * @return 取得的相似方剂
     */
    public List<Prescription> getSimilarPrescription(int pid) {
        IndexFile prescriptionHerbs = prescriptionDao.getIndexFile();
        CalSimilarity cs = new CalSimilarity(prescriptionHerbs);
        Similarity sm = cs.getSimilarElements(defaultSimilarity , pid + "", null);
        
        List<Integer> simIds = sm.getSimilarElements();
        
        return prescriptionDao.getPrescriptions(simIds);
    }
    
    /**
     * 取得与自拟方剂相似中药组成的方剂
     * @param str 自拟方中药组成字符串，格式为：中药名称剂量,中药名称剂量...
     *            例如：大黄8g,黄芪15g....，中间用","分隔符分隔
     * @return 取得的相似方剂
     */
    public List<Prescription> getSimilarPrescription(String str) {
        Prescription p = new Prescription();
        p = p.parseHerb(str);

        IndexFile prescriptionHerbs = prescriptionDao.getIndexFile();
        String pstr = p.getCompositStr();
        prescriptionHerbs.add(pstr);
        
        CalSimilarity cs = new CalSimilarity(prescriptionHerbs);
        Similarity sm = cs.getSimilarElements(defaultSimilarity , p.getId() + "", null);
        
        List<Integer> simIds = sm.getSimilarElements();
        
        return prescriptionDao.getPrescriptions(simIds);
    }    
    /**
     * 适用于多方寒热比较的Jfreechart绘制图的数据集
     * @param ids 比较的方剂
     * @return 数据集
     */
    public DefaultCategoryDataset getHCCompare(List<String> ids) {
        DefaultCategoryDataset dcs = null;
        if (ids != null) {
            List<Integer> idis = null;
            for (String id : ids) {
                idis = new ArrayList<Integer>();
                idis.add(Integer.parseInt(id));
            }
            List<Prescription> pres = prescriptionDao.getPrescriptions(idis);
            Prescriptions ps = new Prescriptions();
            dcs = ps.compare(pres);
        }
        return dcs;
    }
    
    /**
     * 解析自拟方
     * @param str 有中药剂量单位构成的自拟方剂，自拟方中药组成字符串，格式为：中药名称剂量,中药名称剂量...
     *            例如：大黄8g,黄芪15g....，中间用","分隔符分隔
     * @return 自拟方剂
     */
    public Prescription parsePrescription(String str) {
        Prescription p = new Prescription();
        p = p.parseHerb(str);

        return p;
    }

}